
// Copyright (C) 2009 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Derm.BindGen
{
	/// <summary>
	/// Enumeration.
	/// </summary>
	public class Enum
	{
		#region Constructors & Destructor
		
		/// <summary>
		/// Enum constructor.
		/// </summary>
		/// <param name="eName">
		/// A <see cref="System.String"/>
		/// </param>
		/// <param name="eValue">
		/// A <see cref="System.Int32"/>
		/// </param>
		public Enum(string eName)
		{
			mName = eName;
		}
		
		#endregion
		
		#region Enumeration Name
		
		/// <summary>
		/// Enumeration name.
		/// </summary>
		public string Name
		{
			get { return (mName); }
		}
		
		/// <summary>
		/// Enumeration name.
		/// </summary>
		private string mName = null;
		
		#endregion
		
		#region Enumeration Values
		
		/// <summary>
		/// Enumeration value.
		/// </summary>
		public class Value
		{
			#region Constructors & Destructor

			/// <summary>
			/// Value constructor.
			/// </summary>
			/// <param name="eName">
			/// A <see cref="System.String"/> specifying the forward enumeration name. This is
			/// used to determine which enumeration symbol represent this value.
			/// </param>
			/// <param name="eValueName">
			/// A <see cref="System.String"/> specifying the enumeration symbol name. This is
			/// used to determine which enumeration symbol represent this value.
			/// </param>
			/// <param name="eForwardedComment">
			/// A <see cref="System.String"/> specify the comment line to declare when defining
			/// this enuemration value.
			/// </param>
			public Value(string eName, string vName, string eForwardedComment)
			{
				Debug.Assert((eName != null) && (eName.Length > 0));
				Debug.Assert((vName != null) && (vName.Length > 0));
				Debug.Assert((eForwardedComment != null) && (eForwardedComment.Length > 0));

				// Store value name
				mName = vName;
				// Store comment
				mForwardComment = eForwardedComment;
				// Forwarded value
				mForward = true;
			}

			/// <summary>
			/// Value constructor.
			/// </summary>
			/// <param name="eValueName">
			/// A <see cref="System.String"/>
			/// </param>
			/// <param name="vValue">
			/// A <see cref="System.String"/>
			/// </param>
			public Value(string vName, string vValue)
			{
				Debug.Assert((vName != null) && (vName.Length > 0));
				Debug.Assert((vValue != null) && (vValue.Length > 0));

				// Store value symbol name and value
				mName = vName;
				mValue = vValue;
			}

			#endregion

			#region Symbol Name & Value

			/// <summary>
			/// Symbol name.
			/// </summary>
			public string Name
			{
				get { return (mName); }
				set { mImplementationName = value; }
			}

			/// <summary>
			/// Implementation name.
			/// </summary>
			public string ImplementationName
			{
				get { if (mImplementationName == null) return (mName); else return (mImplementationName); }
				set { mImplementationName = value; }
			}

			/// <summary>
			/// Symbol value.
			/// </summary>
			public string ValueString
			{
				get {
					if (mForward == true)
						return (mForwardComment);
					else
						return (mValue);
				}

				set {
					Debug.Assert(IsForwarded == false);
					mValue = value;
				}
			}

			/// <summary>
			/// Forward symbol name.
			/// </summary>
			public bool IsForwarded
			{
				get { return (mForward); }
			}

			public List<string> NameAliases = new List<string>();

			/// <summary>
			/// Value name.
			/// </summary>
			private string mName = null;
			/// <summary>
			/// Name used in implementation.
			/// </summary>
			private string mImplementationName = null;
			/// <summary>
			/// Enumeration value meaning. 
			/// </summary>
			private string mValue = null;
			/// <summary>
			/// Indicates to comment this enumeration value.
			/// </summary>
			private bool mForward = false;
			/// <summary>
			/// 
			/// </summary>
			private string mForwardComment = null;

			#endregion

			#region Enumeration Value Definition

			public void Deprecate()
			{
				mDeprecated = true;
			}

			public bool IsDeprecated
			{
				get { return (mDeprecated); }
			}

			public string GetEnumerationDocumentation()
			{
				if (mForward == false) {
					if (IsDeprecated == true)
						return (String.Format("Value for {0} symbol ({1}) (DEPRECATED).", mName, mValue));
					else
						return (String.Format("Value for {0} symbol ({1}).", mName, mValue));
				} else
					return (null);
			}

			public string GetEnumerationDeclaration()
			{
				if (mForward == false) {
					string eType, eValue = mValue;

					if (eValue.StartsWith("0x") == true) {
						if ((eValue.Length > 10) || (eValue.EndsWith("ull"))) {		// 0xXXXXXXXXXXull
							// Remove ull suffix
							eValue = mValue.Substring(0, eValue.Length-3);
							eType = "ulong";
						} else if (eValue.Length == 10) {							// 0xXXXXXXXX
							eType = "uint";
						} else														// 0xXXXX
							eType = "int";
					} else
						eType = "int";

					return ("public const "+eType+" "+ImplementationName+" = "+eValue+";");
				} else {
					return ("// "+mForwardComment);
				}
			}

			/// <summary>
			/// Enumeration value deprecation
			/// </summary>
			private bool mDeprecated = false;

			#endregion
		}
		
		public void AddValue(Value v)
		{
			mValues.AddLast(v);
		}

		public void RemoveValue(Value v)
		{
			mValues.Remove(v);
		}

		public void DeprecateValue(Value value)
		{
			foreach (Value v in mValues) {
				if (v.Name == value.Name)
					v.Deprecate();
			}
		}
		
		public IEnumerable<Value> Values
		{
			get { return (mValues); }
		}

		public int ValuesCount
		{
			get { return (mValues.Count); }
		}
		
		/// <summary>
		/// Enumeration values.
		/// </summary>
		private LinkedList<Value> mValues = new LinkedList<Value>();
		
		#endregion
	}
}
